#include "CCanvas.h"
#include "CAbacus.h"

BEGIN_EVENT_TABLE(CCanvas, wxScrolledWindow)
EVT_PAINT(CCanvas::OnPaint)
EVT_LEFT_UP(CCanvas::OnLeftButtonUp)
EVT_KEY_UP(CCanvas::OnKeyUp)
END_EVENT_TABLE()

CCanvas::CCanvas(wxWindow *lpParentFrame): wxScrolledWindow(lpParentFrame)
{
    lpbr[0] = wxBrush(wxColor(192, 192, 192));
    lpbr[1] = wxBrush(wxColor(192, 192, 255));
    lpbr[2] = wxBrush(wxColor(255, 192, 192));
    lpbr[3] = wxBrush(wxColor(255, 192, 255));
    lpbr[4] = wxBrush(wxColor(192, 255, 192));
    lpbr[5] = wxBrush(wxColor(192, 255, 255));
    lpbr[6] = wxBrush(wxColor(255, 255, 192));
    frame_width = abacus.m_digit * DIGITAL_INTERVAL;
    stick_top = TOP_Y + FRAME_THICKNESS / 2;
    up_stone_top = TOP_Y + FRAME_THICKNESS;
    beam_top = up_stone_top + STONE_HEIGHT * 2;
    down_stone_top = beam_top + BEAM_THICKNESS;
    down_frame_top = down_stone_top + STONE_HEIGHT * 5;
    stick_left = LEFT_X + DIGITAL_INTERVAL / 2 - STICK_DIAMETER / 2;
    stone_left = LEFT_X + DIGITAL_INTERVAL / 2 - STONE_WIDTH / 2;
    stick_height = BEAM_THICKNESS + STONE_HEIGHT * 7 + FRAME_THICKNESS;
    text_x = LEFT_X + DIGITAL_INTERVAL / 2;
    text_y = TOP_Y / 2;
    //ctor
}

void CCanvas::OnSize(wxSizeEvent &event)
{
    ;
}

void CCanvas::OnPaint(wxPaintEvent &event)
{
    wxPaintDC dc(this);
    dc.SetBackground(*wxWHITE_BRUSH);
    dc.Clear();
    DrawSticks(dc);
    DrawFramesAndBeam(dc);
    DrawStones(dc);
    DrawNumber(dc);
}

void CCanvas::OnLeftButtonUp(wxMouseEvent &event)
{
    wxCoord x, y;
    int i, j, k;
    event.GetPosition(&x, &y);
    i = (x - LEFT_X) / DIGITAL_INTERVAL;
    j = (y - up_stone_top) / STONE_HEIGHT;
    k = (y - down_stone_top) / STONE_HEIGHT;
    if (i >= 0 && i < int(abacus.m_digit))
    {
        if (j >= 0 && j < 2)
        {
            if (j == 0 && abacus.m_lpComponents[i] < 5)
            {
                abacus.m_lpComponents[i] += 5;
            }
            if (j == 1 && abacus.m_lpComponents[i] >= 5)
            {
                abacus.m_lpComponents[i] -= 5;
            }
        }
        if (k >= 0 && k < 5)
        {
            if (k < int(abacus.m_lpComponents[i] % 5))
            {
                abacus.m_lpComponents[i] -= (abacus.m_lpComponents[i] % 5 - k);
            }
            if (k > int(abacus.m_lpComponents[i] % 5))
            {
                abacus.m_lpComponents[i] += (k - abacus.m_lpComponents[i] % 5);
            }
        }
    }
    Refresh();
}

void CCanvas::OnKeyUp(wxKeyEvent &event)
{
    int iKeyCode;
    iKeyCode = event.GetKeyCode();
    switch(iKeyCode)
    {
    case 'c':
    case 'C':
        abacus.data_clear();
        break;
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        abacus.move_right((unsigned int)(iKeyCode - int('0')));
        break;
    case WXK_NUMPAD0:
    case WXK_NUMPAD1:
    case WXK_NUMPAD2:
    case WXK_NUMPAD3:
    case WXK_NUMPAD4:
    case WXK_NUMPAD5:
    case WXK_NUMPAD6:
    case WXK_NUMPAD7:
    case WXK_NUMPAD8:
    case WXK_NUMPAD9:
        abacus.move_right((unsigned int)(iKeyCode - WXK_NUMPAD0));
        break;
    }
    Refresh();
}

void CCanvas::DrawSticks(wxPaintDC &dc)
{
    unsigned int i;
    dc.SetPen(*wxBLACK_PEN);
    dc.SetBrush(*wxWHITE_BRUSH);
    for (i = 0; i < abacus.m_digit; ++i)
    {
        dc.DrawRectangle(stick_left + i * DIGITAL_INTERVAL, stick_top, STICK_DIAMETER, stick_height);
    }
}

void CCanvas::DrawFramesAndBeam(wxPaintDC &dc)
{
    dc.SetPen(*wxBLACK_PEN);
    dc.SetBrush(*wxWHITE_BRUSH);
    dc.DrawRectangle(LEFT_X, TOP_Y, frame_width, FRAME_THICKNESS);
    dc.DrawRectangle(LEFT_X, beam_top, frame_width, BEAM_THICKNESS);
    dc.DrawRectangle(LEFT_X, down_frame_top, frame_width, FRAME_THICKNESS);
}

void CCanvas::DrawStones(wxPaintDC &dc)
{
    unsigned int i, j;
    for (i = 0; i <abacus.m_digit; ++i)
    {
        dc.SetBrush(lpbr[i % 7]);
        if (abacus.m_lpComponents[i] < 5)
        {
            dc.DrawEllipse(stone_left + i * DIGITAL_INTERVAL, up_stone_top, STONE_WIDTH, STONE_HEIGHT);
        }
        else
        {
            dc.DrawEllipse(stone_left + i * DIGITAL_INTERVAL, up_stone_top + STONE_HEIGHT, STONE_WIDTH, STONE_HEIGHT);
        }
        if (abacus.m_lpComponents[i] % 5 > 0)
        {
            for (j = 0; j < abacus.m_lpComponents[i] % 5; ++j)
            {
                dc.DrawEllipse(stone_left + i * DIGITAL_INTERVAL, down_stone_top + STONE_HEIGHT * j, STONE_WIDTH, STONE_HEIGHT);
            }
        }
        if (abacus.m_lpComponents[i] % 5 < 4)
        {

            for (j = 0; j < 4 - abacus.m_lpComponents[i] % 5; ++j)
            {
                dc.DrawEllipse(stone_left + i * DIGITAL_INTERVAL, down_frame_top - STONE_HEIGHT * (j + 1), STONE_WIDTH, STONE_HEIGHT);
            }
        }
    }
}

void CCanvas::DrawNumber(wxPaintDC &dc)
{
    unsigned int i;
    bool bShowZero;
    wxCoord width, height;
    wxString wxstrText;
    dc.SetFont(wxFont(FONT_SIZE, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
    bShowZero = false;
    for (i = 0; i < abacus.m_digit; ++i)
    {
        if (abacus.m_lpComponents[i] > 0 || bShowZero || i == abacus.m_digit - 1)
        {
            bShowZero = true;
            wxstrText = wxString::Format("%d", abacus.m_lpComponents[i]);
            dc.GetTextExtent(wxstrText, &width, &height);
            dc.DrawText(wxstrText, text_x + DIGITAL_INTERVAL * i - width / 2, text_y - height / 2);
        }
    }
}
